package com.hmdp;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;

/**
 * Created by sneaker on 2017/4/23.
 */
public class SignValidatorDemo {
    private static final Logger LOG = LoggerFactory.getLogger(SignValidatorDemo.class);

    private static ObjectMapper objectMapper = new ObjectMapper();
    private static final String APPKEY="4048808900";
    private static final String SECRETKEY="ef876eaf993b55941c584e37120be241";
    private static final String USERNAME="100201";
    private static final String PASSWORD="quality@2022";
    private static final String SCOPE="quality_scope";
    private static final String GRANT_TYPE="client_credentials";
//    private static final String baseUrl="http://beijing-gateway-3rd.app-dev.bjev.com.cn";//测试
        private static final String baseUrl="https://beijing-gateway-3rd.app-prod.bjev.com.cn";//正式

    public static String getSign(CheckSignData data,String secretKey) {
        StringBuilder signature = new StringBuilder();
        signature.append(data.getHttpMethod()).append(data.getUrl());
        //处理header的签名内容
        preSignForHeaders(signature, data);
        //处理参数的签名内容
        preSignForParameters(signature, data);
        signature.append(secretKey);
        byte[] signBytes = null;
        try {
            LOG.info("sign before url encode: {}", signature);
            String sign = signature.toString().replaceAll(" ", "");
            signBytes = URLEncoder.encode(sign, "UTF-8").getBytes("UTF-8");
            LOG.info("sign url encode: {}", new String(signBytes));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("验签拼接失败", e);
        }
        String sign = sha256Digest(signBytes);
        LOG.info("sign result: {}", sign);
        return sign;
    }

    public static String toHexString(byte[] digestBytes) {
        StringBuilder hexStr = new StringBuilder();
        for(byte b : digestBytes) {
            hexStr.append(String.format("%02x", b & 0xff));
        }
        return hexStr.toString();
    }

    public static String sha256Digest(byte[] content) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("SHA-256");
            return toHexString(md5.digest(content));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param signature
     * @param data
     */
    private static void preSignForHeaders(StringBuilder signature, CheckSignData data) {
        try {
            //处理header
            Map<String, String> headers = data.getHeaderData();
            TreeMap<String, String> sortHeaders = new TreeMap<String, String>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.toLowerCase().compareTo(o2.toLowerCase());
                }
            });
            for (Map.Entry<String, String> header : headers.entrySet()) {
                if (header.getKey().startsWith("ice") && !"ice-auth-sign".equals(header.getKey())) {
                    sortHeaders.put(header.getKey(), header.getValue());
                }
            }
            for (Map.Entry<String, String> header : sortHeaders.entrySet()) {
                signature.append(header.getKey().toLowerCase()).append(":").append(header.getValue());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void preSignForParameters(StringBuilder signature, CheckSignData data) {
        try {
            Map<String, String> parameters = data.getParameterData();
            if (parameters==null) {
                parameters = new HashMap<>();
            }
            if (StringUtils.isNotBlank(data.getContentType()) &&
                    data.getContentType().toLowerCase().contains("application/json")
                    && (StringUtils.isNotBlank(data.getContentData()))) {
                parameters.put("json", data.getContentData().replaceAll("\\s", "").replaceAll("\\n", ""));
                //parameters.put("json", data.getContentData().replaceAll("\\n", ""));
            }
            TreeMap<String, String> sortParameters = new TreeMap<String, String>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return o1.toLowerCase().compareTo(o2.toLowerCase());
                }
            });
            sortParameters.putAll(parameters);
            for (Map.Entry<String, String> parameter : sortParameters.entrySet()) {
                signature.append(parameter.getKey().toLowerCase()).append("=").append(String.valueOf(parameter.getValue()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @ApiModel
    @Data
    @Builder
    public static class CheckSignData {
        @ApiModelProperty("待签名url")
        private String url;
        @ApiModelProperty("appKey")
        private String appKey;
        @ApiModelProperty("待签名http method")
        private String httpMethod;
        private Map<String, String> parameterData;
        @ApiModelProperty("待签名request body参数，map的json字符串")
        private String contentData;
        @ApiModelProperty("待签名header参数,map的json字符串")
        private Map<String, String> headerData;
        @ApiModelProperty("待签名content-type参数")
        private String contentType;
        @ApiModelProperty("待验证时间戳")
        private Long timestamp;
        @ApiModelProperty("服务id")
        private String serviceId;

    }


    public static void postByHttpClient(String url) {
        try {
            long timeStamp = System.currentTimeMillis();
            Map<String,String> params=new HashMap<>();
            params.put("grant_type",GRANT_TYPE);
            params.put("scope",SCOPE);

            Map<String,String> headerMap = new HashMap<>();
            headerMap.put("ice-auth-appkey",APPKEY);
            headerMap.put("ice-auth-timestamp",timeStamp+"");

//            String headerData="{\"ice-auth-appkey\":\"APPKEY\",\"ice-auth-timestamp\":\"TIMESTAMP\"}".replace("TIMESTAMP",String.valueOf(timeStamp)).replace("APPKEY", APPKEY);
            CheckSignData checkSignData = CheckSignData.builder()
                    .url("/beijing-auth-iam-account/oauth/token")
                    .appKey(APPKEY)
                    .httpMethod("POST")
//                    .parameterData("{\"grant_type\":\"client_credentials\",\"scope\":\"scopevalue\"}".replace("scopevalue",SCOPE))
                    .parameterData(params)
                    .contentData(null)
                    .headerData(headerMap)
                    .contentType("application/x-www-form-urlencoded;charset=UTF-8")
                    .timestamp(timeStamp)
                    .serviceId(null)
                    .build();
            String sign = getSign(checkSignData,SECRETKEY);

            HttpClient client = HttpClients.createDefault();// 打开浏览器


            CredentialsProvider provider = new BasicCredentialsProvider();
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USERNAME, PASSWORD);
            provider.setCredentials(AuthScope.ANY, credentials);

//            client= HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();

            HttpPost post = new HttpPost(url);// 输入网址
            //            post.addHeader("ice-auth-appkey","2762810351");
            //            post.addHeader("ice-auth-sign","580047bd0ad77e93705641af6a9ab98c53b7a1f3b0d70636ec7dc64da9965c1111");
            //            post.addHeader("ice-auth-timestamp","1669607627371");
            post.addHeader("ice-auth-appkey",APPKEY);
            post.addHeader("ice-auth-sign",sign);
            post.addHeader("ice-auth-timestamp",timeStamp+"");
            post.addHeader("content-type","application/x-www-form-urlencoded;charset=UTF-8");


            String auth = USERNAME + ":" + PASSWORD;
            auth = new String(Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8)));
            System.out.println("auth="+auth);
            post.addHeader("Authorization", "Basic " + auth);


            List parameters = new ArrayList();
            parameters.add(new BasicNameValuePair("grant_type", "client_credentials"));
            parameters.add(new BasicNameValuePair("scope", SCOPE));
            post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"));
            HttpResponse response = client.execute(post); // 执行post
            HttpEntity entity = response.getEntity(); // 获取响应数据
            String result = EntityUtils.toString(entity); // 将响应数据转成字符串
            System.out.println(result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    public static void postByHttpClientNew(String url) {
        try {
            long timeStamp = System.currentTimeMillis();
            Map<String,String> params=new HashMap<>();
            params.put("grant_type",GRANT_TYPE);
            params.put("scope",SCOPE);

            Map<String,String> headerMap = new HashMap<>();
            headerMap.put("ice-auth-appkey",APPKEY);
            headerMap.put("ice-auth-timestamp",timeStamp+"");

//            String headerData="{\"ice-auth-appkey\":\"APPKEY\",\"ice-auth-timestamp\":\"TIMESTAMP\"}".replace("TIMESTAMP",String.valueOf(timeStamp)).replace("APPKEY", APPKEY);
            CheckSignData checkSignData = CheckSignData.builder()
                    .url("/beijing-auth-iam-account/oauth/token")
                    .appKey(APPKEY)
                    .httpMethod("POST")
//                    .parameterData("{\"grant_type\":\"client_credentials\",\"scope\":\"scopevalue\"}".replace("scopevalue",SCOPE))
                    .parameterData(params)
                    .contentData(null)
                    .headerData(headerMap)
                    .contentType("application/x-www-form-urlencoded;charset=UTF-8")
                    .timestamp(timeStamp)
                    .serviceId(null)
                    .build();
            String sign = getSign(checkSignData,SECRETKEY);

            HttpClient client = HttpClients.createDefault();// 打开浏览器


            CredentialsProvider provider = new BasicCredentialsProvider();
            UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USERNAME, PASSWORD);
            provider.setCredentials(AuthScope.ANY, credentials);

//            client= HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();

            HttpPost post = new HttpPost(url);// 输入网址
            //            post.addHeader("ice-auth-appkey","2762810351");
            //            post.addHeader("ice-auth-sign","580047bd0ad77e93705641af6a9ab98c53b7a1f3b0d70636ec7dc64da9965c1111");
            //            post.addHeader("ice-auth-timestamp","1669607627371");
            post.addHeader("ice-auth-appkey",APPKEY);
            post.addHeader("ice-auth-sign",sign);
            post.addHeader("ice-auth-timestamp",timeStamp+"");
            post.addHeader("content-type","application/x-www-form-urlencoded;charset=UTF-8");


            String auth = USERNAME + ":" + PASSWORD;
            auth = new String(Base64.getEncoder().encode(auth.getBytes(StandardCharsets.UTF_8)));
            System.out.println("auth="+auth);
            post.addHeader("Authorization", "Basic " + auth);


            List parameters = new ArrayList();
            parameters.add(new BasicNameValuePair("grant_type", "client_credentials"));
            parameters.add(new BasicNameValuePair("scope", SCOPE));
            post.setEntity(new UrlEncodedFormEntity(parameters, "UTF-8"));
            HttpResponse response = client.execute(post); // 执行post
            HttpEntity entity = response.getEntity(); // 获取响应数据
            String result = EntityUtils.toString(entity); // 将响应数据转成字符串
            System.out.println(result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

//    public static void main(String[] args) {
//        CheckSignData checkSignData = CheckSignData.builder()
//                .url("/beijing-auth-iam-account/oauth/token")
//                .appKey("2762810351")
//                .httpMethod("POST")
//                .parameterData("{\"grant_type\":\"client_credentials\",\"scope\":\"c62x_scope\"}")
//                .contentData(null)
//                .headerData("{\"ice-auth-appkey\":\"2762810351\",\"ice-auth-sign\":\"4fbb3d78e3b9154963f6d278533e58c9c8ba4039bf0ac811126e1fcdb24fa6a4\",\"ice-auth-timestamp\":\"1669620502553\"}")
//                .contentType("application/x-www-form-urlencoded;charset=UTF-8")
//                .timestamp(1669620502553L)
//                .serviceId(null)
//                .build();
//        String sign = getSign(checkSignData,"secretKey");
//        postByHttpClient("https://beijing-gateway-3rd.app-dev.bjev.com.cn/beijing-auth-iam-account/oauth/token");
//    }
    public static void main(String[] args) {

        postByHttpClient(baseUrl+"/beijing-auth-iam-account/oauth/token");
    }
}
